package com.xnyy.lottery.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.StrUtil;
import com.xnyy.lottery.common.exception.CustomException;
import com.xnyy.lottery.domain.vo.MemberRegisterParkingInfoVO;
import lombok.extern.slf4j.Slf4j;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashAttributeSet;
import javax.print.attribute.standard.PrinterName;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterAbortException;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import static com.xnyy.lottery.util.GoogleBarCodeUtils.getBarCode;
import static java.awt.image.BufferedImage.*;
import static java.awt.print.Printable.NO_SUCH_PAGE;
import static java.awt.print.Printable.PAGE_EXISTS;

/**
 * 打印工具
 *
 * @Author xiesh
 * @Date 2022-09-21 15:04
 * @Version 1.0
 */
@Slf4j
public class PrintUtils {
    public static void print(MemberRegisterParkingInfoVO registerParkingInfo, Integer type) {
        print(new Print(registerParkingInfo, type), null);
    }

    private static void print(Printable print, String printerName) {
        Book book = new Book();
        // 打印格式
        PageFormat pf = new PageFormat();
        // 原点在纸张的左上方，x 指向右方，y 指向下方。
        pf.setOrientation(PageFormat.PORTRAIT);
        // 通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
        Paper p = new Paper();
        // 页面宽度 页面高度
        p.setSize(145, 500);

        // x轴 y轴 宽度 高度
        p.setImageableArea(0, 0, 145, 500);
        pf.setPaper(p);
        // 把 PageFormat 和 Printable 添加到书中，组成一个页面
        book.append(print, pf);
        // 指定打印机打印（printerName打印机名称）
        PrintService service = getSpecifyPrintServices(printerName);
        if (execPrint(book, service)) {
            return;
        }
        // 获取默认打印服务对象
        service = lookupDefaultPrintService();
        if (execPrint(book, service)) {
            return;
        }
        // 获取打印服务对象
        throw new CustomException("打印失败");
    }

    private static boolean execPrint(Book book, PrintService service) {
        if (service == null) {
            log.error("打印服务为空");
            return false;
        }
        try {

            PrinterJob job = PrinterJob.getPrinterJob();
            // 写入书
            job.setPageable(book);
            // 添加指定的打印机
            job.setPrintService(service);
            // 打印执行
            job.print();
            return true;
        } catch (PrinterException e) {
            log.error("================打印出现异常", e);
            if (e instanceof PrinterAbortException) {
                throw new CustomException("终止打印");
            }
            return false;
        }
    }

    private static PrintService getSpecifyPrintServices(String printerName) {
        if (printerName == null || printerName.length() <= 0) {
            return null;
        }
        HashAttributeSet hs = new HashAttributeSet();
        hs.add(new PrinterName(printerName, null));
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, hs);
        if (services.length == 0) {
            throw new CustomException("无法找到打印机：" + printerName);
        }
        return services[0];
    }

    protected static PrintService lookupDefaultPrintService() {
        PrintService service = PrintServiceLookup.lookupDefaultPrintService();

        /* Pageable implies Printable so checking both isn't strictly needed */
        //DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
        if (service != null &&
                service.isDocFlavorSupported(
                        DocFlavor.SERVICE_FORMATTED.PAGEABLE) &&
                service.isDocFlavorSupported(
                        DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
            return service;
        } else {
            PrintService[] services =
                    PrintServiceLookup.lookupPrintServices(
                            DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
            if (services.length > 0) {
                return services[0];
            }
        }
        return null;
    }

    public static void print(BufferedImage backgroundRemoval, String printerName) {
        print((g, pf, page) -> {
                    if (page > 0) {
                        return NO_SUCH_PAGE;
                    }
                    Graphics2D g2d = (Graphics2D) g;
                    // 设置颜色
                    g2d.setColor(Color.BLACK);
                    g2d.drawImage(ImgUtil.scale(backgroundRemoval, 0.6f), 0, 0, null);
                    return PAGE_EXISTS;
                },
                printerName
        );
    }

    static class Print implements Printable {
        private final MemberRegisterParkingInfoVO registerParkingInfo;
        private final Integer type;

        Print(MemberRegisterParkingInfoVO registerParkingInfo, Integer type) {
            this.registerParkingInfo = registerParkingInfo;
            this.type = type;
        }

        // 设置小票打印
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
            if (page > 0) {
                return NO_SUCH_PAGE;
            }
            Graphics2D g2d = (Graphics2D) g;
            // 设置颜色
            g2d.setColor(Color.BLACK);
            //模式  字体   字体大小
            g2d.setFont(new Font("Default", Font.PLAIN, 15));
            //A区，序号10
            g2d.drawString(StrUtil.addSuffixIfNot(registerParkingInfo.getRegion(), "区") + registerParkingInfo.getSerialNumber(), 45, 20);
            //条码
            BufferedImage image = getBarCode(registerParkingInfo.getBarCode());
            g2d.drawImage(image, 10, 40, null);
            //type: 1序号打印，2结果打印
            if (type != null && type == 2 && StrUtil.isNotBlank(registerParkingInfo.getDescribe())) {
                g2d.setFont(new Font("Default", Font.PLAIN, 10));

                g2d.drawString("位置：" + StrUtil.trimToEmpty(registerParkingInfo.getDescribe()), 8, 60 + image.getHeight());
                g2d.drawString("时间：" + StrUtil.trimToEmpty(DateUtil.formatDateTime(registerParkingInfo.getAllocationTime())), 8, 80 + image.getHeight());
            }
            g2d.drawString("   ", 8, 100 + image.getHeight());
            return PAGE_EXISTS;
        }

    }
}
